package org.sunrise.game.center.server;

import org.sunrise.game.center.client.ReportClientManager;
import org.sunrise.game.center.message.ReportMessage;
import org.sunrise.game.common.network.client.BaseClientManager;
import org.sunrise.game.common.network.server.BaseServerManager;
import org.sunrise.game.common.utils.IdGenerator;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class NodeManager {
    public static int NODE_TYPE_EXTERNAL = 1;
    public static int NODE_TYPE_GAME = 2;
    public static int NODE_TYPE_HTTP = 3;
    public static int NODE_TYPE_RPC_NODE = 4;
    public static int INTERVAL = 2000;

    // 节点id-节点信息
    public static Map<String, NodeData> datasByNodeId = new HashMap<>();

    // 节点类型-此类型的所有节点
    public static Map<Integer, Map<String, NodeData>> datasByType = new HashMap<>();

    public static void updateNode(ReportMessage reportMessage) {
        NodeData nodeData = datasByNodeId.get(reportMessage.getNodeId());
        if (nodeData == null) {
            nodeData = new NodeData(reportMessage.getNodeId());
        }
        nodeData.setType(reportMessage.getType());
        nodeData.setIp(reportMessage.getIp());
        nodeData.setPort(reportMessage.getPort());
        nodeData.setServerId(reportMessage.getServerId());
        nodeData.setReportTime(System.currentTimeMillis());
        datasByNodeId.put(reportMessage.getNodeId(), nodeData);

        Map<String, NodeData> dataMap = datasByType.get(reportMessage.getType());
        if (dataMap == null) {
            dataMap = new HashMap<>();
        }
        dataMap.put(reportMessage.getNodeId(), nodeData);
        datasByType.put(reportMessage.getType(), dataMap);
    }

    public static void broadcast() {
        for (Map.Entry<Integer, Map<String, NodeData>> entry : datasByType.entrySet()) {
            if (entry.getKey() == NODE_TYPE_EXTERNAL) {
                // 对外服 无需广播

            } else if (entry.getKey() == NODE_TYPE_GAME) {
                // game 需广播所有对外服的信息
                Map<String, NodeData> games = entry.getValue();
                for (Map.Entry<String, NodeData> gameNodes : games.entrySet()) {
                    // 此节点已失效
                    if (gameNodes.getValue().getReportTime() + INTERVAL * 2L < System.currentTimeMillis()) {
                        continue;
                    }
                    for (ReportMessage message : buildBroadcastData(NODE_TYPE_EXTERNAL, gameNodes.getKey())) {
                        BaseServerManager.sendToClient(message);
                    }
                }
            } else if (entry.getKey() == NODE_TYPE_RPC_NODE) {
                // rpc服 需广播所有rpc信息
                Map<String, NodeData> globals = entry.getValue();
                for (Map.Entry<String, NodeData> globalNodes : globals.entrySet()) {
                    // 此节点已失效
                    if (globalNodes.getValue().getReportTime() + INTERVAL * 2L < System.currentTimeMillis()) {
                        continue;
                    }
                    for (ReportMessage message : buildBroadcastData(NODE_TYPE_RPC_NODE, globalNodes.getKey())) {
                        BaseServerManager.sendToClient(message);
                    }
                }
            } else if (entry.getKey() == NODE_TYPE_HTTP) {
                // http模块 需广播所有对外服信息和game服信息
                Map<String, NodeData> https = entry.getValue();
                for (Map.Entry<String, NodeData> httpNodes : https.entrySet()) {
                    // 此节点已失效
                    if (httpNodes.getValue().getReportTime() + INTERVAL * 2L < System.currentTimeMillis()) {
                        continue;
                    }
                    for (ReportMessage message : buildBroadcastData(NODE_TYPE_EXTERNAL, httpNodes.getKey())) {
                        BaseServerManager.sendToClient(message);
                    }
                    for (ReportMessage message : buildBroadcastData(NODE_TYPE_GAME, httpNodes.getKey())) {
                        BaseServerManager.sendToClient(message);
                    }
                }
            }
        }
    }

    private static List<ReportMessage> buildBroadcastData(int need, String toNode) {
        List<ReportMessage> messages = new ArrayList<>();
        Map<String, NodeData> dataMap = datasByType.get(need);
        if (dataMap == null) {
            return messages;
        }
        for (NodeData nodeData : dataMap.values()) {
            // 自己的信息不用发
            if (nodeData.getNodeId().equals(toNode)) {
                continue;
            }
            // 两次都没收到上报，说明已经失效
            if (nodeData.getReportTime() + INTERVAL * 2L < System.currentTimeMillis()) {
                continue;
            }
            // 对外服、rpc服上报的ip为空，无效
            if (nodeData.getIp() == null) {
                if (need == NODE_TYPE_EXTERNAL || need == NODE_TYPE_RPC_NODE) {
                    continue;
                }
            }
            ReportMessage message = new ReportMessage();
            message.setMessageId(IdGenerator.getId());
            message.setType(need);
            message.setNodeId(CenterServerManager.getCenterServerNodeId());
            message.setToNodeId(toNode);
            message.setIp(nodeData.getIp());
            message.setPort(nodeData.getPort());
            message.setServerId(nodeData.getServerId());

            messages.add(message);
        }
        return messages;
    }

    public static void report(String clientNode) {
        if (ReportClientManager.getReportClient(clientNode).getConnectToCenter().getServerChannel() == null) {
            return;
        }
        ReportMessage message = new ReportMessage();
        message.setNodeId(clientNode);
        message.setType(ReportClientManager.getReportClient(clientNode).getType());
        message.setIp(ReportClientManager.getReportClient(clientNode).getClientIp());
        message.setPort(ReportClientManager.getReportClient(clientNode).getClientPort());
        message.setServerId(ReportClientManager.getReportClient(clientNode).getServerId());

        BaseClientManager.sendToServer(message);
    }
}
